package ipcards.rulesets;

import ipcards.CardSet;
import ipcards.Deck;
import ipcards.Card;
import ipcards.Game;
import ipcards.GameBase;
import ipcards.PlayerModel;
import ipcards.Room;
import ipcards.Table;
import ipcards.events.PlayerAction;
import ipcards.net.Client;
import ipcards.net.CardsServer;

import java.awt.Point;
import javax.swing.*;
import java.awt.event.*;
import java.util.Vector;
import java.util.HashMap;

public class ThreeUpThreeDownGame extends GameBase implements Game {

	//actions
	private static final char PLAY_CARDS = 0;
	private static final char PICK_UP_DECK = 1;
	private static final char SET_FACE_UPS = 2;
	
	
	

	
	private ActionListener al;
	public JPanel buttonPanel;
	private JButton playCards;
	private JButton pickUpDeck;
	private JButton swapFaceUps;
	
	private ThreeUpThreeDownRuleSet ruleset;
	private String TUTDDeckName;
	private Room room;
	private CardSet TUTDDeck;
	private static int numplayersleft;
	private boolean[] playersOut;
	private HashMap<Client, Vector<CardSet>> playerCards;
	public Vector<Card> discards;
	public CardSet deck;
	public Card discardTop;
	private boolean playClockwise = true;
	private boolean fillhand = true;		//used so that when a jack is played in 2player, the other person doesnt fill their hand.
	public int numDecksToAdd;
	
	
	//Called only on SERVER end?
	public ThreeUpThreeDownGame(PlayerModel player, Room r, Client source) {
		super(player);
		room = r;
		
		//createButtonPanel();
		//send to view 
		//server1 = systemtoplevel.getCardServer();
		ruleset = new ThreeUpThreeDownRuleSet(room.controller.getCardServer(), this);
		TUTDDeckName = ruleset.getDeckName();						//method needed in ChaseTheAceRuleSet
		
		room.table.addDeck(new Deck(TUTDDeckName));
		
		int count = 0; //count is the number of extra decks that need to be added to each client
		while((room.players.size() * 9) >= room.table.cards.size()){
System.out.println("added extra deck");			
			room.table.addDeck(new Deck(TUTDDeckName));
			count++;
		}
		numDecksToAdd = count;
//System.out.println("epsilonon"+count);		
		room.table.addDecksNumber = numDecksToAdd;
			
		TUTDDeck = room.table.cards;
		TUTDDeck.shuffle();
		deck = new CardSet();
		
		if(room.players.size() != 1) {
			
			int sourceID = 0;
			CardsServer cardsserver = room.controller.getServer();
			for(Client c: cardsserver.clients){
				if(c == source){
					break;
				}
				sourceID++;
			}
			
			playerCards = new HashMap<Client, Vector<CardSet>>(room.players.size());
			
			CardsServer x = room.controller.getServer();
			
			for(Client c: x.clients){
				Vector sets = new Vector(3);
				sets.add(new CardSet());	
				sets.add(new CardSet());
				sets.add(new CardSet());
				playerCards.put(c, sets);
			}
				
			ruleset.setDealerID(sourceID);
			ruleset.deal((room.players.size() - 1), TUTDDeck);			//subtract 1 to compensate for server not being a client
			int i = 0;
			//System.out.println("server");
System.out.println("dealt");				
			playersOut = new boolean[x.clients.size()];
			int clientnum = 0;
			
			discards = new Vector<Card>();
			discardTop = null;
			
			for(Client c : x.clients) {
				//System.out.println(i++);
System.out.println("about to resetlf");					
				x.resetLocalFlip();
System.out.println("resetlf");					
				playersOut[clientnum] = false;
				clientnum++;
			}											//use this (server end) to set static variable numplayersleft equal to number of players; decrement numplayersleft for each pass thru else (client); when numplayersleft is zero (indicating last player), call SYNC_LOCATIONS (see below)
			numplayersleft = room.players.size() - 1;
		}
	}
	
	
	//called only from CLIENT end?
	//Only relevant if extra decks have been added due to too many people
	public ThreeUpThreeDownGame(PlayerModel player, Room r, Client source, int numExtraDecks) {
		super(player);
		room = r;
		
		//createButtonPanel();
		//send to view 
		//server1 = systemtoplevel.getCardServer();
		ruleset = new ThreeUpThreeDownRuleSet(room.controller.getCardServer(), this);
		TUTDDeckName = ruleset.getDeckName();						//method needed in ChaseTheAceRuleSet
		
		room.table.addDeck(new Deck(TUTDDeckName));
		
		int count = 0; //count is the number of extra decks that need to be added to each client
		while((room.players.size() * 9) >= room.table.cards.size()){
System.out.println("added extra deck");			
			room.table.addDeck(new Deck(TUTDDeckName));
			count++;
		}
//System.out.println("pion"+numExtraDecks);		
		numDecksToAdd = numExtraDecks;
		if(room.players.size() == 1) {	//at client end
//System.out.println("piiswin");		
			while(numDecksToAdd > 0){
//System.out.println("pi");
				room.table.addDeck(new Deck(TUTDDeckName));
				numDecksToAdd--;
			}
		}
	
		TUTDDeck = room.table.cards;
		TUTDDeck.shuffle();
		deck = new CardSet();
		
		if(room.players.size() != 1) {
			
			int sourceID = 0;
			CardsServer cardsserver = room.controller.getServer();
			for(Client c: cardsserver.clients){
				if(c == source){
					break;
				}
				sourceID++;
			}
			
			playerCards = new HashMap<Client, Vector<CardSet>>(room.players.size());
			
			CardsServer x = room.controller.getServer();
			
			for(Client c: x.clients){
				Vector<CardSet> sets = new Vector<CardSet>(3);
				sets.add(new CardSet());	
				sets.add(new CardSet());
				sets.add(new CardSet());
				playerCards.put(c, sets);
			}
				
			ruleset.setDealerID(sourceID);
			ruleset.deal((room.players.size() - 1), TUTDDeck);			//subtract 1 to compensate for server not being a client

			//System.out.println("server");
//System.out.println("dealt");				
			playersOut = new boolean[CardsServer.clients.size()];			
			discards = new Vector<Card>();
			discardTop = null;
			

			x.resetLocalFlip();
			
			for(boolean b:playersOut) {
			//for(int clientnum = 0; clientnum < CardsServer.clients.size(); clientnum++) {
				b = false;
			}											//use this (server end) to set static variable numplayersleft equal to number of players; decrement numplayersleft for each pass thru else (client); when numplayersleft is zero (indicating last player), call SYNC_LOCATIONS (see below)
			numplayersleft = room.players.size() - 1;
		}
	}
//what calls the below method.....it may be possible to have firstly a bar that forces a player only to set their face ups (and does so ONCE ONLY), THEN put in a new panel that has only playCards and pickUpDeck	
	//Generic methods
	public JPanel createButtonPanel(){
		buttonPanel = new JPanel();
		al = new buttonPanelListener();
		playCards = new JButton("Play Selected Cards");
			playCards.setMnemonic(KeyEvent.VK_P);
			playCards.addActionListener(al);
		pickUpDeck = new JButton("Pick Up Deck");
			pickUpDeck.setMnemonic(KeyEvent.VK_U);
			pickUpDeck.addActionListener(al);
		swapFaceUps = new JButton("Swap Face Up Cards");
			swapFaceUps.setMnemonic(KeyEvent.VK_S);
			swapFaceUps.addActionListener(al);	
				
		buttonPanel.add(playCards);
		buttonPanel.add(pickUpDeck);
		buttonPanel.add(swapFaceUps);
		return buttonPanel;
	}
	
	/*public JPanel createEmptyButtonPanel(){
		buttonPanel = new JPanel();
		al = new buttonPanelListener();
		//no buttons added
		return buttonPanel;
	}*/
	
	public class buttonPanelListener implements ActionListener{
		public void actionPerformed(ActionEvent ae) {
				
			Object source = ae.getSource();
			if(source == playCards){	
//System.out.println("played card IDs (not Immutable IDs) are: "+	room.players.get(0).selectedCards);				
				player.performPlayerAction(PlayerAction.newCustomPlayerAction(this, PLAY_CARDS, room.players.get(0).selectedCards, null));		//"player" is a PlayerModel
						
				//player.performPlayerAction(PlayerAction.newCustomPlayerAction(this, PLAY_CARDS, room.players.get(0).selectedCards.toString()));
				}
			else if(source == pickUpDeck){
				player.performPlayerAction(PlayerAction.newCustomPlayerAction(this, PICK_UP_DECK, null));		//EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT 			
			}
			else if(source == swapFaceUps){
				player.performPlayerAction(PlayerAction.newCustomPlayerAction(this, SET_FACE_UPS, room.players.get(0).selectedCards, null));
			}
		}
	}
	
/*IN FUTURE, USE THIS METHOD TO CONTROL THE DISPLAY ARRANGEMENT OF A PLAYERS HAND (e.g. SUIT ORDER, NUMERICAL ORDER, NUMERICAL ORDER WITHIN A SUIT, etc)	*/
	
	public void setDisplayZOrder(Client c, CardSet cards, int order){
		

	}
	
	public Room getRoom() {
		return room;
	}
	
	public Point getPlayerLocationFixed(int playerNumber) {				 
		int numPlayers = room.players.size() - 1;
		
		switch(numPlayers){
			
			//return new Point(15+(150*playerNumber)%1050, 15+(((150*playerNumber)/1050)*150));
			
			
			case 1:	return new Point(15, 15);
			
			case 2: 
				/*			0	1	2
				  	_____________________
				   0|		hand    0	|
				   1|		face up 0	|
				   2|		 			|
				   3|		  dis dk	|				//NOTE: "dis" means "discards" and "dk means "deck"
				   4|					|
				   5|		1 pu ecaf	|				//NOTE: read these lines backwards
				   6|		1    dnah	|
				    ^^^^^^^^^^^^^^^^^^^^^
				*/
				switch(playerNumber){
					case 0:	return new Point(15, 15);
					
					case 1:	return new Point((int)(15+(150*2)%1050), (int)(15+((150*5/1050)*150)));
				}
				
				
			case 3:
				/*			0	1 	2 	3 	4	5	6	7	8
						________________________________________
				    0	|			0	0		fa	ha			|
				   0.5  |	 	nd	up				ce	nd		|
				    1	|	ha	ce 						up	1	|
				   1.5  |	fa								1	|
				    2	|		 								|
				   		|										|
				    3	|				dis dk					|
				   		|										|
				    4	|										|
				    	|										|
				    5	|		  		2 pu ecaf				|
				    	|										|
				    6	|				2    dnah				|
				    	|										|
				    	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
				*/
				switch(playerNumber){
					case 0:	return new Point(15, (int)(15+((150/1050)*150)));
					
					case 1:	return new Point((int)(15+(150*5)%1050), 15);
					
					case 2:	return new Point((int)(15+(150*5)%1050), (int)(15+(((150*5)/1050)*150)));
				}
				
			case 4:
				/*			0	1 	2 	3 	4	5	6	
						_________________________________
				    0	|			hand    0           |
				    1	|			face up 0			|	
				    2	|	3	3				fa	ha	|
				    3	|		up	  dis dk	ce	nd	|
				    4	|	nd	ce				up		|
				    5	|	ha	fa				1	1	|
				    6	|			2 pu ecaf			|
				    7	|			2	 dnah			|
				    	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
				*/
				switch(playerNumber){
					case 0:	return new Point((int)(15+(150*2)%1050), 15);
					
					case 1:	return new Point((int)(15+(150*5)%1050), (int)(15+((150*2/1050)*150)));
					
					case 2:	return new Point((int)(15+(150*4)%1050), (int)(15+(((150*6)/1050)*150)));
					
					case 3:	return new Point(15, (int)(15+(((150*5)/1050)*150)));
				}
				
			case 5:
				/*			0	1/3	2/3	1 	4/3	5/3	2 	.	.	3 	.	.	4	.	.	5	.	.	6	.	.	7	.	.	8	.	.	9	.	.	10	.	.
						_________________________________________________________________________________________________________________________________________
				    0	|													0	.	.				ha	.	.													|
				   1/3 	|	 									-	.	.	.	.	.				.	.	.	nd	.	.										|
				   2/3	|							nd	.	.	.	.	.	.	.	.				.	.	.	.	.	.	-	.	.							|
				    1	|				ha	.	.	.	.	.	.	.	.	0	.	.				fa	.	.	.	.	.	.	.	.	1	.	.				|
				   4/3  |				.	.	.	.	.	.	up	.	.	.	.	.				.	.	.	ce	.	.	.	.	.	.	.	.				|
				   5/3	|				.	.	.	ce	.	.	.	.	.	.	.	.				.	.	.	.	.	.	up	.	.	.	.	.				|
				    2	|				fa	.	.	.	.	.	.	.	.										.	.	.	.	.	.	1	.	.				|
				   	.	|				.	.	.	.	.	.																.	.	.	.	.	.				|
				    .	|				.	.	.																						.	.	.				|
				   	3	|																																		|
				   	.	|																																		|
				   	.	|																																		|
				    4	|	4	.	.	4	.	.								  dis .	  .	  dk  .	  .									fa	.	.	ha	.	.	|
				    .	|	.	.	.	.	.	.								  .	  .	  .	  .	  .	  .									.	.	.	.	.	.	|
				    .	|	.	.   .	.	.	.	.							  .	  .	  .	  .	  .	  .									.	.	.	.	.	.	|
				    5	|		-	.	.	pu	.	.																				ce	.	.	nd	.	.		|
				    .	|		.	.	.	.	.	.																				.	.	.	.	.	.		|	
				    .	|		.	.	.	.	.	.																				.	.	.	.	.	.		|
				    6	|			nd	.	.	ce	.	.																		up	.	.	-	.	.			|
				    .	|			.	.	.	.	.	.																		.	.	.	.	.	.			|
				    .	|			.	.	.	.	.	.																		.	.	.	.	.	.			|
				    7	|				ha	.	.	fa	.	.																2	.	.	2	.	.				|
				    .	|				.	.	.	.	.	.																.	.	.	.	.	.				|
				    .	|				.	.	.	.	.	.																.	.	.	.	.	.				|
				    8	|											  3   .	  .	  pu  .	  .	  ec  .	  .	  af  .	  .												|
				    .	|											  .	  .	  .	  .	  .	  .	  .	  .	  .	  .	  .	  .												|
				    .	|											  .	  .	  .	  .	  .	  .	  .	  .	  .	  .	  .	  .												|		
				    9	|											  3	  .	  .	  -   .	  .	  dn  .	  .	  ah  .	  .												|
				    .	|											  .	  .	  .	  .	  .	  .	  .	  .	  .	  .	  .	  .												|	
				    .	|											  .	  .	  .	  .	  .	  .	  .	  .	  .	  .	  .	  .												|			
				    	^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
				    											3	 3.5	4	 4.5	5	 5.5	6	 6.5	7	 7.5	8
				*/
				switch(playerNumber){
					case 0:	return new Point((int)(15+150%1050), (int)(15+((150/1050)*150)));
					
					case 1:	return new Point((int)(15+(150*6)%1050), 15);
					
					case 2:	return new Point((int)(15+(150*9)%1050), (int)(15+(((150*4)/1050)*150)));
					
					case 3:	return new Point((int)(15+(150*6.5)%1050), (int)(15+(((150*8)/1050)*150)));
					
					case 4:	return new Point((int)(15+(150*2)%1050), (int)(15+(((150*7)/1050)*150)));
				}
				
			//case 6:
				/*
					1	|
					2	|
					3	|
					4	|
					5	|
					6	|
					7	|
				/
				switch(playerNumber){
					case 0:	return new Point(15+(150*playerNumber)%1050, 15+(((150*playerNumber)/1050)*150));
					
					case 1:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 2:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 3:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 4:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 5:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
				}
				
			case 7:
				switch(playerNumber){
					case 0:	return new Point(15+(150*playerNumber)%1050, 15+(((150*playerNumber)/1050)*150));
					
					case 1:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 2:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 3:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 4:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 5:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 6:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
				}
				
			case 8:
				switch(playerNumber){
					case 0:	return new Point(15+(150*playerNumber)%1050, 15+(((150*playerNumber)/1050)*150));
					
					case 1:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 2:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 3:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 4:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 5:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 6:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
					
					case 7:	return new Point(15+(150*playerNumber)%1050, 15+(((150*3*playerNumber)/1050)*150));
				}
				*/
			default:
				System.out.println("The system is not yet capable of handling more than 8 players. \n Please wait for further updates to the system or reduce the number of players");						
				
				int value = 150*playerNumber;								//EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT
				int xpos = (value%1050);									//EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT
				int ypos = (value/1050)*150;								//EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT
				//System.out.println(xpos+","+ypos);						//EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT
				return new Point(15 + xpos,15+(ypos*150));	//EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT
		}
	}
	
	//Returns the orientation of the player as an array of integers (in the format [x, y]) representing the displacement from one card to the next,
	//with +x corresponding to left, and +y corresponding to down
	public int[] getPlayerDirectionVariable(int playerNumber, boolean overlap) {	//Not currently used in CTA
		int[] blah = new int[2];
		return blah;													//EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT EDIT
	}
	
	//Returns the central point of a players hand, about which all cards are situated
	public Point getPlayerLocationCircle(int playerNumber) {
		int numPlayers = room.players.size() - 1;
		double angle = 360/(numPlayers);
//		System.out.println(angle);
		//double radius = 300+(numPlayers-1)*3;					//WILL NEED ADJUSTMENT
		double radius = 300;
		
		int x = (int)(radius * Math.cos(Math.toRadians(playerNumber*angle + 90)));
		int y = (int)(radius * Math.sin(Math.toRadians(playerNumber*angle + 90)));
		return new Point(x+465,y+465);
	}
	
	//Returns the orientation of all players as an array of integers (in the format [x, y]) representing the displacement from one card to the next,
	//with +x corresponding to left, and +y corresponding to down
	public int[] getPlayerDirectionFixed() {	//Not currently used in CTA
		int[] dir = new int[2];
		dir[0] = 150%1050;
		dir[1] = 0;
		return dir;	
	}
	
	
	
	
	public void addPlayerCard(Client client, Card card, int cardType){
		Vector<CardSet> pCards = (Vector<CardSet>)(playerCards.get(client));
		CardSet pCardsSpecific = (CardSet)(pCards.elementAt(cardType));
		pCardsSpecific.add(card);
	}
	
	public void removePlayerCard(Client client, Card card, int cardType){
		Vector<CardSet> pCards = (Vector<CardSet>)(playerCards.get(client));
		CardSet pCardsSpecific = (CardSet)(pCards.elementAt(cardType));
		pCardsSpecific.remove(card);
	}
	
	public int queryPlayerCard(Client client, Card card){
		Vector<CardSet> pCards = playerCards.get(client);
		CardSet hand = (CardSet)(pCards.elementAt(2));
		if(hand.contains(card)){
			return 2;
		}
		CardSet faceUps = (CardSet)(pCards.elementAt(1));
		if(faceUps.contains(card)){
			return 1;
		}
		CardSet faceDowns = (CardSet)(pCards.elementAt(0));
		if(faceDowns.contains(card)){
			return 0;
		}
		return -1;
	}
	
	public int[] queryPlayerHand(Client client){
		Vector<CardSet> pCards = (Vector<CardSet>)(playerCards.get(client));
		CardSet hand = (CardSet)(pCards.elementAt(2));
		CardSet faceUps = (CardSet)(pCards.elementAt(1));
		CardSet faceDowns = (CardSet)(pCards.elementAt(0));
		int[] sizes = new int[3];
		sizes[0] = faceDowns.size();
		sizes[1] = faceUps.size();
		sizes[2] = hand.size();
		return sizes;
	}
	public CardSet getFaceDowns(Client client){
		Vector<CardSet> pCards = (Vector<CardSet>)(playerCards.get(client));
		CardSet faceUps = (CardSet)(pCards.elementAt(0));
		return faceUps;
	}
	
	public CardSet getFaceUps(Client client){
		Vector<CardSet> pCards = (Vector<CardSet>)(playerCards.get(client));
		CardSet faceUps = (CardSet)(pCards.elementAt(1));
		return faceUps;
	}
	
	public CardSet getHand(Client client){
		Vector<CardSet> pCards = (Vector<CardSet>)(playerCards.get(client));
		CardSet hand = (CardSet)(pCards.elementAt(2));
		return hand;
	}
	
	
	public void playerActionPerformed(PlayerAction pa) {
		if(room.players.size() != 1) {
					//System.out.println("FOR THE LOVE OF GOD AND EVERYTHING ELSE THAT IS HOLY.....IM AT THE SERVER!!!!!!!!!!");
			if(ruleset.canNewGame){
				return;
			}		
			
			switch (pa.getCustomAction()) {
			
			case PLAY_CARDS:
				//System.out.println("SERVER RECIEVED play");
				Client current2 = ((Client)(pa.getSource()));
//SELECTEDCARDS MUST BE SET ------pa.getArgs()?.....can be, but MUST BE SET TO BE SO
//				System.out.println(pa.getArgs());
				String args = pa.getArgs();
				String[] parts = args.split(":");
				if(parts.length != 4){
					System.out.println("WTF has happened....string splitting too many times!!!!");
				}
				String numCards = parts[0].trim();
				String cardIDNumDigits = parts[1].trim();
				String cardIDNumbers = parts[2].trim();
				int numCardsInt = Integer.parseInt(numCards);
//System.out.println(numCards + ":" + cardIDNumDigits + ":" + cardIDNumbers);				
				
				CardSet selectedCards = new CardSet();	
				int IDpos = 0;
				
				for(int i=0;i<numCardsInt;i++){
//System.out.println(i + ": first loop start");					
					int IDnumdigits = Integer.parseInt(Character.toString(cardIDNumDigits.charAt(i)));
//System.out.println("IDnumdigits: " + IDnumdigits);					
					String ID = "";
					for(int j=0;j<IDnumdigits;j++){
//System.out.println(j + ": second loop start : " + IDpos);
						ID = ID + cardIDNumbers.charAt(IDpos);
						IDpos++;
					}
//System.out.println("second loop end: " + ID);	
//					int cardImmutableID = Integer.parseInt(ID);
//					for(Card c:	TUTDDeck){
//						if(c.getImmutableID() == cardImmutableID){
//System.out.println(c.toString() + ":" + c.getImmutableID());							
//							selectedCards.add(c);
//						}
//					}
					
int cardImmutableID = Integer.parseInt(ID);
for(Card c:	TUTDDeck){
	if(c.getID() == cardImmutableID){
System.out.println(c.toString() + ":" + c.getImmutableID());							
		selectedCards.add(c);
	}
}					
							
					//Card c = TUTDDeck.getCardFromID(Integer.parseInt(ID));
//System.out.println(c.toString() + ":" + c.getImmutableID());					
					//selectedCards.add(c);
				}
					
					
//					System.out.println(numCardsInt + ":" + selectedCards.size() + ": aseklfdhlqkerjhflkasdjbhfvlakhdsflsahdflkauhsdlfkjhasdlifuhalisduh");	
					
//System.out.println(selectedCards.toString());							
				int success = ruleset.playCards(selectedCards,discardTop,current2);
				
				switch (success) {
				
				case ThreeUpThreeDownRuleSet.SUCCESS:
						ruleset.setEndFaceUpChange(current2);		//will prevent future changes to face up cards
					break;
				
				case ThreeUpThreeDownRuleSet.FACE_DOWN:
					if(current2.getServerModel() != null)
						current2.getServerModel().performPlayerAction(PlayerAction.newShowDialog(this, "The face down card played is not legal in the current situation. You are picking up the deck."));
					return;
						
				default:
					if(current2.getServerModel() != null)
						current2.getServerModel().performPlayerAction(PlayerAction.newShowDialog(this, "You cant do that you fool!!!"));
					return;
				}
				
			
				
				//update clients
				//current2.getServerModel().sync();
				if(fillhand){		
					ruleset.fillHand(getPreviousPlaying(current2));
				}
				fillhand = true;
				//update clients
				//current2.getServerModel().sync();
				querySetPlayerOut(current2);
				
				setDisplayZOrder(current2, selectedCards, 0);
				//update clients
				current2.getServerModel().sync();
			break;
			
			case PICK_UP_DECK:
				//System.out.println("SERVER RECIEVED draw");
				if(discards.size() == 0){
					System.out.println("There are no cards to pick up");
					return;
				}
				pickUpDeck(((Client)(pa.getSource())));
				ruleset.setEndFaceUpChange(((Client)(pa.getSource())));	
			break;
			
			case SET_FACE_UPS:
				Client current3 = ((Client)(pa.getSource()));
								String args2 = pa.getArgs();
				String[] parts2 = args2.split(":");
				if(parts2.length != 4){
					System.out.println("WTF has happened....string splitting too many times!!!!");		//should be "number of cards:number of digits in each card ID number (so for id 0-9 would be 1, for 10-99 would be 2, etc.numbers are concatenated):actual ID numbers of cards"
				}
				String numCards2 = parts2[0].trim();
				int numCardsInt2 = Integer.parseInt(numCards2);		
				String cardIDNumDigits2 = parts2[1].trim();
				String cardIDNumbers2 = parts2[2].trim();
								
				CardSet selectedCards2 = new CardSet();	
				int IDpos2 = 0;
				
				for(int i=0;i<numCardsInt2;i++){				
					int IDnumdigits2 = Integer.parseInt(Character.toString(cardIDNumDigits2.charAt(i)));					
					String ID2 = "";
					for(int j=0;j<IDnumdigits2;j++){
						ID2 = ID2 + cardIDNumbers2.charAt(IDpos2);
						IDpos2++;
					}
					int cardImmutableID2 = Integer.parseInt(ID2);
					for(Card c:	TUTDDeck){
//						if(c.getImmutableID() == cardImmutableID2){
if(c.getID() == cardImmutableID2){							
//System.out.println(c.toString() + ":" + c.getImmutableID());							
							selectedCards2.add(c);
						}
					}		
				}	
				System.out.println(selectedCards2.toString());
				
				int result = ruleset.setStartFaceUps(current3,selectedCards2);
				
				if(result != 0){
					switch(result){
					case 1:
		System.out.println("One or more cards selected is not acceptable as a face up card. You must select 3 cards such that each card is either in your current hand or is a current face up card. These 3 cards will then become your face up cards");			
					break;
					case 2:
		System.out.println("You have not selected the correct number of cards. You must select 3 cards such that each card is either in your current hand or is a current face up card. These 3 cards will then become your face up cards");
					break;			
					case 3:	
		System.out.println("You have already started playing the game. Therefore you cannot change your face up cards");
					break;
					}
				}				
				
				//update clients
				current3.getServerModel().sync();
			break;	
			}
		}
	}
	
	public void pickUpDeck(Client playing){
		ruleset.pickUpDeck(playing);
		room.table.sModel.sync();
		playClockwise = !(playClockwise);			//reverse direction so that previous becomes next
		endTurn(playing);							//move turn to next (really previous) player
		playClockwise = !(playClockwise);			//reset play direction to what it was before this method call
	}
	
	public void reverseDirection(){
		playClockwise = !(playClockwise);		
	}
	
	public void unsetFillHand(){
		fillhand = false;
	}
	
	public void endTurn(Client playing){
		if(playClockwise){
			//play in 'forward' direction....simply end turn
			playing.endTurn();									//end current players turn
			
//System.out.print("PlayersOut array: ");
int cnt=0;
int num=-1;
for(Client c: CardsServer.clients){
	if(c==playing)
		num=cnt;
	if(playersOut[cnt])
		System.out.print("true, ");
	else
		System.out.print("false, ");
	cnt++;
}
//System.out.println("\n"+"current client is number "+num);			
			
			Client next2 = null;							//find next player
			int currentID2 = 0;
			boolean iscurrent2 = false;
			for(Client c: CardsServer.clients){
				if(iscurrent2){
					next2 = c;
					if(playersOut[currentID2]){				//if player is out
						next2.endTurn();						//end their turn and try the next player on the list
						next2 = null;
						iscurrent2 = true;					//hypothetically still with current player
					}
					else{
						iscurrent2 = false;					//found next player who is not out...it is now their turn
						//System.out.println("set next in endturn 3^3vgame forward");
					}
				}
				if(c == playing){
					iscurrent2 = true;						//found current player....start searching for the next still in player on the list
					//System.out.println("found current in endturn 3^3vgame forward");
				}
				
				currentID2++;
			}
			
			if(next2 == null){								//reached the end of the list and still no next player?
				boolean isNull2 = true;						//repeat process starting from top of list
				currentID2 = 0;
				for(Client c: CardsServer.clients){
					if(!playersOut[currentID2]){				//if player is not out
						next2 = c;							//set next player and exit

						isNull2 = false;
						break;
					}
					c.endTurn();							//otherwise, move on to the next player
					currentID2++;
				}
			}
		}
		else{
			//play is anticlockwise, or backwards, so must complete a reverse end turn
			playing.endTurnReverse();	
			Client newplaying = playing;
			CardsServer cs = room.controller.getCardServer();
//System.out.print("PlayersOut array: ");
int cnt=0;
int num=-1;
for(Client c: cs.clients){
	if(c==newplaying)
		num=cnt;
	if(playersOut[cnt])
		System.out.print("true, ");
	else
		System.out.print("false, ");
	cnt++;
}
//System.out.println("\n"+"current client is number "+num);			
			while(true){
				playClockwise = !(playClockwise);
				Client previous = getPrevious(newplaying);
				playClockwise = !(playClockwise);
				int prevnum = 0;
				for(Client c: cs.clients){
					if(c == previous){
						break;
					}
					prevnum++;
				}
//System.out.println("Previous client is client number: "+prevnum);				
				if(playersOut[prevnum]){		//previous is already out, need to be skipped....go round the loop again
					previous.endTurnReverse();
					newplaying = previous;		//update client to its predecessor for next loop
//System.out.println("Executing clause and player is out");				
				}
				else{							//player is in the game....is now their turn
					return;
				}
			}				
		}
	
	}
	
	public int numPlayersIn(){
		return numplayersleft;
	}
	
	public void clearDiscards(){
		for(Card c: discards){
			c.setLocation(1,1);
			c.setFaceDown();
		}
		discards.clear();
		discardTop = null;
	}
	
	public Client getPreviousPlaying(Client playing){	//return the previous player still in the game
		CardsServer cs = room.controller.getCardServer();
		
		if(playClockwise){
			Client previous = null;
			boolean prevSet = false;
			int playernum = 0;
			for(Client c: cs.clients){
				if(c == playing && prevSet){		//if previous has NOT been set, then the current player is the first on the list, so this if clause will never be run
					return previous;
				}
				if(!playersOut[playernum]){
					previous = c;
					prevSet = true;
				}
				playernum++;
			}
		
			playernum = 0;
			int lastnum = cs.clients.size()-1;
			for(Client c: cs.clients){		//if the above comment holds true, the client that needs to be returned is the last on the list
				if(lastnum == playernum){
					return c;
				}
				playernum++;
			}

			System.out.println("this statement should never be reached");
			return playing;
		}
		else{
//problem here somewhere			
			Client next = null;				//as play is reversed, the next player on the list is the previous player in the game
			int currentID = 0;
//int currentID = playersOut.length-1;			
			boolean iscurrent = false;
			for(Client c: cs.clients){
				if(iscurrent){
					next = c;
					if(playersOut[currentID]){				//if player is out
						next = null;						//try the next player on the list
						iscurrent = true;					//hypothetically still with current player
System.out.println("player "+currentID+" is out");
					}
					else{
						iscurrent = false;					//found next player who is not out
						return next;
					}
				}
				if(c == playing){
					iscurrent = true;						//found current player....start searching for the next still in player on the list
				}
				
				currentID++;
//currentID--;				
			}
			
			if(next == null){								//reached the end of the list and still no next player? The next in player is earlier in the list than the current player
				boolean isNull = true;						//repeat process starting from top of list
				currentID = 0;
//currentID = playersOut.length-1;				
				for(Client c: cs.clients){
					if(!playersOut[currentID]){				//if player is not out
						next = c;							//set next player and exit
						isNull = false;
						return next;
					}
					currentID++;							//otherwise, move on to the next player
//currentID--;				
				}
			}
			
			System.out.println("this statement should never be reached");
			return playing;
		}		
	}
	
	public Client getPrevious(Client playing){	//return the previous player even if they are out
		CardsServer cs = room.controller.getCardServer();
		if(playClockwise){
		
			Client previous = null;
			boolean prevSet = false;
			int playernum = 0;
			for(Client c: cs.clients){
				if(c == playing && prevSet){		//if previous has NOT been set, then the current player is the first on the list, so this if clause will never be run
					return previous;
				}
				
				previous = c;
				prevSet = true;		//ensures that if the current player is first on the list, previous will still be set
				
				playernum++;
			}
			
			playernum = 0;
			int lastnum = cs.clients.size()-1;
			for(Client c: cs.clients){		//if the above comment holds true, the client that needs to be returned is the last on the list
				if(lastnum == playernum){
					return c;
				}
				playernum++;
			}	

			System.out.println("this statement should never be reached");
			return playing;		
		}
		else{
			Client next = null;				//as play is reversed, the next player on the list is the previous player in the game
			int currentID = 0;
			boolean iscurrent = false;
			for(Client c: cs.clients){
				if(iscurrent){
					next = c;
					iscurrent = false;					//found next player who is not out
					return next;
					
				}
				if(c == playing){
					iscurrent = true;						//found current player....start searching for the next still in player on the list
				}
				
				currentID++;
			}
			
			if(next == null){								//reached the end of the list and still no next player? The next in player is earlier in the list than the current player
				boolean isNull = true;						//repeat process starting from top of list
				currentID = 0;
				for(Client c: cs.clients){
					next = c;							//set next player and exit
					isNull = false;
					return next;
				}
			}
			
			System.out.println("this statement should never be reached");
			return playing;
		}
	}	
	
	public int getPlayerNum(Client client){
		int playernum = 0;
		CardsServer cs = room.controller.getCardServer();
		for(Client c: cs.clients){
			if(c == client){
				return playernum;
			}
			playernum++;
		}
		return -1;
	}
	
	public void resetLocalFlip(Card card){
		CardSet temp = new CardSet();
		temp.add(card);
		room.table.sModel.performPlayerAction(new PlayerAction(room.table.sModel, PlayerAction.RESET_LOCAL_FLIP, temp.toString()));
	}

	public void querySetPlayerOut(Client player){	//determines if the given player has just gone out
		int[] hand = queryPlayerHand(player);
		boolean winner = true;
		int playernum = -1;
		if(hand[0] == 0 && hand[1] == 0 && hand[2] == 0){
			//player is out
			for(int i=0;i<playersOut.length;i++){
				if(playersOut[i]){
					winner = false;
				}
				if(room.controller.getCardServer().clients.get(i) == player){
					playersOut[i] = true;
					playernum = i;
				}
			}
			numplayersleft--;
			if(winner){
				System.out.println("Player "+playernum+" is the winner");
			}
		}
//System.out.println("pretest");		
		if(numplayersleft <= 1){
			ruleset.canNewGame = true;
			//NEED A WAY OF STOPPING GAME HERE!!!!!	--- DONE!!!
System.out.println("Game is over");
			//turn all cards face up
			//remove all permissions except allowing new game to be started (effectively stops game)
			for(int i=0;i<playersOut.length;i++){
				Client isLast = room.controller.getCardServer().clients.get(i);
				CardSet hnd = getHand(isLast);
				CardSet FUs = getFaceUps(isLast);
				CardSet FDs = getFaceDowns(isLast);
				
				if(playersOut[i] = true){
//System.out.println("Player out is player "+i+" with "+hnd.size()+" hand cards and "+FDs.size()+" face down cards");
					for(Card cHand: hnd){
						cHand.setFaceUp();
					}
					for(Card cFD: FDs){
						cFD.setFaceUp();
						//set "face down" card (now face up) positions just above/below original face up cards

						cFD.setLocation(new Point((int)(cFD.getLocation().getX()), (int)(cFD.getLocation().getY()+15)));
					}
				//isLast.getServerModel().sync();	
				}
				/*for(Card cHand: hnd){
					ruleset.changePermissions(0, cHand, isLast);
				}
				for(Card cFU: FUs){
					ruleset.changePermissions(0, cFU, isLast);
				}
				for(Card cFD: FDs){
					ruleset.changePermissions(0, cFD, isLast);
				}*/
			}
	
			player.getServerModel().sync();	
			
//implement notice that the game is over, new game must be started....to display when a player attempts to move a card(s)
//remove turn system so anyone can start a new game		
		}
	}
	
	public boolean legalityCheck(String option){
		if(option.equalsIgnoreCase("shuffle")){
			return ruleset.canShuffle;
		}
		if(option.equalsIgnoreCase("newgame")){
			return ruleset.canNewGame;
		}
		return false;
	}
	
	public boolean queryIsPlayerOut(int clientNumber){
		return playersOut[clientNumber];
	}	
}

